package tt.love.hw.servlet;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.LazyDynaBean;
import org.apache.commons.beanutils.LazyDynaClass;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.Form;
import org.apache.commons.validator.Validator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.ValidatorException;
import org.apache.commons.validator.ValidatorResources;
import org.apache.commons.validator.ValidatorResult;
import org.apache.commons.validator.ValidatorResults;

import tt.love.hw.common.ActionContext;
import tt.love.hw.common.ActionException;
import tt.love.hw.common.ActionMapping;
import tt.love.hw.common.ResourceBundleContext;
import tt.love.hw.common.ViewRender;
import tt.love.hw.common.config.FormBean;

@SuppressWarnings("serial")
public class ColasServlet extends HttpServlet {

	Logger log = LoggerFactory.getLogger(ColasServlet.class);

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		process(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		process(req, resp);
	}

	protected void process(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		DynaBean dynamicform = createDynamicForm(req, resp);
		ActionContext actionContext = initActionContext(req, resp, dynamicform);
		if(!processValidation(req, actionContext, dynamicform)){
			ViewRender viewRender = new ViewRender(((ActionMapping) getServletContext().getAttribute(
			"ActionMapping")).getErrorPage(req.getServletPath()));
			viewRender.render(actionContext);
			return;
		}
		String requestURL = req.getServletPath();
		req.setAttribute("preURL", requestURL);
		req.setAttribute("preContext", actionContext);
		try {
			ViewRender viewRender = ((ActionMapping) getServletContext()
					.getAttribute("ActionMapping")).getActionExecutor(
					requestURL).execute(actionContext);
			Iterator<String> key = actionContext.keyIterator();
			while (key.hasNext()) {
				String param = key.next();
				req.setAttribute(param, actionContext.get(param));
			}

			actionContext.setRequest(req);
			viewRender.render(actionContext);
		} catch (ActionException e) {
			log.error("Action Execute Exeption", e);
			req.setAttribute("COLAS_EEORR", e);
			throw e;
		}

	}

	private ActionContext initActionContext(HttpServletRequest req,
			HttpServletResponse resp, DynaBean dynamicform) {
		ActionContext actionContext = new ActionContext(req, resp);

		if (dynamicform != null) {
			DynaProperty properties[] = dynamicform.getDynaClass()
					.getDynaProperties();
			if (properties != null) {
				int len = properties.length;
				for (int i = 0; i < len; i++) {
					String name = properties[i].getName();
					actionContext.put(name, dynamicform.get(name));
				}

			}
		} else {
			Enumeration<?> params = req.getParameterNames();
			while (params.hasMoreElements()) {
				String param = (String) params.nextElement();
				Object value = req.getParameter(param);

				if (value != null)
					actionContext.put(param, value);
			}
		}
		return actionContext;
	}

	private DynaBean createDynamicForm(HttpServletRequest req,
			HttpServletResponse resp) {
		FormBean formbean = ((ActionMapping) getServletContext().getAttribute(
				"ActionMapping")).getActionForm(req.getServletPath());
		if (formbean != null) {
			LazyDynaClass clazz = new LazyDynaClass(formbean.getId());

			for (Map.Entry<String, String> property : formbean.getProperties()
					.entrySet()) {
				try {
					clazz.add(property.getKey(), Class.forName(property
							.getValue()));
				} catch (ClassNotFoundException e) {
					log.error("Init Form Form", e);
				}
			}
			DynaBean dynamicform = new LazyDynaBean(clazz);
			for (DynaProperty dynaProperty : clazz.getDynaProperties()) {
				try {
					dynamicform.set(dynaProperty.getName(), dynaProperty
							.getType().newInstance());
				} catch (InstantiationException e) {
					log.error("Init Dynamic Form", e);
				} catch (IllegalAccessException e) {
					log.error("Init Form Form", e);
				}
			}
			try {
				BeanUtils.populate(dynamicform, req.getParameterMap());
			} catch (IllegalAccessException e) {
				log.error("Init Form Form", e);
			} catch (InvocationTargetException e) {
				log.error("Init Form Form", e);
			}
			return dynamicform;
		}
		return null;
	}

	private Boolean processValidation(HttpServletRequest req,
			ActionContext actionContext, DynaBean dynamicform) {
		if (dynamicform != null) {
			try {
				ValidatorResources resources = (ValidatorResources) getServletContext()
						.getAttribute("ValidatorResources");
				Validator validator = new Validator(resources, req
						.getServletPath());

				validator.setParameter(Validator.BEAN_PARAM, dynamicform);
				validator.setOnlyReturnErrors(true);
				ValidatorResults results = validator.validate();
				Locale locale = (Locale) ((HttpServletRequest) req)
						.getSession().getAttribute(
								"javax.servlet.jsp.jstl.fmt.locale");
				if(locale==null){
					locale = new Locale("zh","CN");
				}
				ResourceBundleContext resourceBundleContext = (ResourceBundleContext)getServletContext().getAttribute("resourceBundleContext");
				ResourceBundle messages = resourceBundleContext.getResourceBundle(locale);
				boolean success = true;
				List<String> errorList = new ArrayList<String>();
				Form form = resources.getForm(new Locale("",""), req.getServletPath());
				Iterator<?> propertyNames = results.getPropertyNames().iterator();
				while (propertyNames.hasNext()) {
					String propertyName = (String) propertyNames.next();
					Field field = form.getField(propertyName);
					String prettyFieldName = messages.getString(field.getArg(0)
							.getKey());
					ValidatorResult result = results.getValidatorResult(propertyName);
					Iterator<?> keys = result.getActions();
					while (keys.hasNext()) {
						String actName = (String) keys.next();
						ValidatorAction action = resources
								.getValidatorAction(actName);

						if (!result.isValid(actName)) {
							success = false;
							String message = messages.getString(action.getMsg());
							Object[] args = { prettyFieldName };
							errorList.add(MessageFormat.format(message, args));
						}
					}
				}
				req.setAttribute("VALIDATION_ERROR", errorList);
				return success;
			} catch (ValidatorException e) {
				log.error("Validator Exception", e);
				e.printStackTrace();
				return false;
			}

		}
		return true;

	}
}
